﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace LPBToolsLib.NetSocket
{
    public delegate void SocketRecDataCallBack(object sender, Socket ClientSocket, ref byte[] RecData);

    public delegate void SocketRecResponCallBack(object sender, byte[] RecData);

    public class TCPClientSocket
    {
        #region 成员
        public Socket tClientSocket { get; set; }
        private Thread tClientThd { get; set; }

        private bool isConnected = false;
        protected IPEndPoint DestIPEnd { get; set; }

        public event SocketRecDataCallBack OnReceive;

        public Recorder_Error ErrorRecorder { get; set; }
        public Recorder_RTxBytes RTxBytes { get; set; }
        /// <summary>
        /// 服务器地址
        /// </summary>
        public string DestAddress { get { return DestIPEnd.Address.ToString(); } }

        /// <summary>
        /// 服务器监听端口
        /// </summary>
        public int DestPort { get { return DestIPEnd.Port; } }
        /// <summary>
        /// 目标服务器地址及IP信息
        /// </summary>
        public IPEndPoint DestIPEndPoint
        {
            get { return DestIPEnd; }
            set { DestIPEnd = value; }
        }

        /// <summary>
        /// 是否与服务器处于连接状态
        /// </summary>
        public bool IsConnected { get { return isConnected; } }

        public TCPClientSocket()
        {
        }

        public TCPClientSocket(IPEndPoint HostEndPointInfoX)
        {
            DestIPEndPoint = HostEndPointInfoX;
        }
        #endregion
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns>返回是否成功连接到目标地址</returns>
        public bool Connect()
        {
            try
            {
                if (DestIPEndPoint != null)
                {

                    tClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    tClientSocket.Connect(DestIPEndPoint);
                    isConnected = true;

                    // 已经有接收数据处理事件，则启动接收线程
                    if (OnReceive != null)
                    {
                        tClientThd = new Thread(new ThreadStart(ReceiveData));
                        tClientThd.Name = "接收数据";
                        tClientThd.Start();
                    }
                }
                return isConnected;
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
                return false;
            }
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="hostAddress">服务器地址</param>
        /// <param name="port">服务器监听端口</param>
        public bool Connect(IPEndPoint HostEndPointInfoX)
        {
            DestIPEndPoint = HostEndPointInfoX;
            return Connect();
        }
        /// <summary>
        /// 关闭与服务器的连接
        /// </summary>
        public virtual void Close()
        {
            isConnected = false;
            try
            {
                if (tClientThd != null)
                {
                    //fClientThd.Abort();                    
                    tClientThd = null;
                }
                Thread.Sleep(2);
                if (tClientSocket != null)
                {
                    if (tClientSocket.Connected)
                        tClientSocket.Shutdown(SocketShutdown.Both);
                    tClientSocket.Close();
                    tClientSocket = null;
                }
            }
            catch (Exception ex)
            {
                if (ErrorRecorder != null)
                    ErrorRecorder.setRecord(ex);
                else
                    throw ex;
            }
        }
        /// <summary>
        /// 接受数据线程
        /// </summary>
        private void ReceiveData()
        {
            byte[] buff = new byte[1024];
            while ((tClientThd != null) && isConnected)
            {
                try
                {
                    int fRecCount = 0;

                    if ((tClientSocket != null) && tClientSocket.Connected)
                    {
                        // 检查Socket中接收缓冲区中是否收到数据，及数据数量
                        // 此方式将产生阻塞，不会占用CPU运算
                        fRecCount = tClientSocket.Available;
                        //fRecCount= fClientSocket.Receive(buff, SocketFlags.Peek);
                        if (fRecCount > 0)
                        {
                            byte[] fRecBuf = new byte[fRecCount];
                            // 接收数据，并清除接收缓冲区
                            tClientSocket.Receive(fRecBuf, SocketFlags.None);
                            RTxBytes?.setRecord(new Record_Byte("Rx", fRecBuf));
                            OnReceive?.Invoke(this, tClientSocket, ref fRecBuf);
                        }
                    }
                }
                catch (Exception ex)
                {
                    ErrorRecorder?.setRecord(ex);
                }
                // 该方式将会占用大量的CPU运算，建议增加Sleep(1)
                Thread.Sleep(1);
            }
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="fSendStr">数据</param>
        public int Send(string fSendStr)
        {
            RTxBytes?.setRecord(new Record_Byte("Tx", Encoding.UTF8.GetBytes(fSendStr)));
            if (isConnected)
            {
                return tClientSocket.Send(Encoding.UTF8.GetBytes(fSendStr));
            }
            return 0;
        }

        public int Send(byte[] fSendDatas)
        {
            if (tClientSocket.Connected && (tClientSocket != null) && (tClientSocket.Connected))
            {
                RTxBytes?.setRecord(new Record_Byte("Tx", fSendDatas));
                return tClientSocket.Send(fSendDatas);
            }
            return 0;
        }
    }

    public class TCPClientAsync : ContainerBase
    {
        public Socket tClientSocket { get; set; }
        [DisplayName("TCP Socket是否已经连接到目标地址")]
        public bool Connected { get { return (tClientSocket != null) ? tClientSocket.Connected : false; } }
        protected IPEndPoint DestIPEnd { get; set; }

        public event SocketRecResponCallBack OnReceiveRespon;
        public Recorder_Error ErrorRecorder { get; set; }
        /// <summary>
        /// 服务器地址
        /// </summary>
        [DisplayName("目标地址")]
        public string DestEndPoint { get { return DestIPEnd?.ToString(); } }
        /// <summary>
        /// 目标服务器地址及IP信息
        /// </summary>
        public IPEndPoint DestIPEndPoint { get; set; }

        public TCPClientAsync(IPEndPoint tServerEP = null)
        {
            DestIPEndPoint = tServerEP;
        }

        protected byte[] RecBuf { get; } = new byte[8000];
        public bool Connect()
        {
            try
            {
                if (DestIPEndPoint != null)
                {

                    tClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    tClientSocket.Connect(DestIPEndPoint);
                    if (tClientSocket.Connected)
                        tClientSocket.BeginReceive(RecBuf, 0, RecBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), tClientSocket);//向系统投递下一个接收请求
                }
                return (tClientSocket != null) && tClientSocket.Connected;
            }
            catch (Exception ex)
            {
                ErrorRecorder?.setRecord(ex);
                return false;
            }
        }

        private void ReceiveCallBack(IAsyncResult asyncResult)
        {
            if ((tClientSocket != null) && tClientSocket.Connected)
            {
                byte[] tTRBuf = null;
                int length = 0;
                try
                {
                    length = tClientSocket.EndReceive(asyncResult);
                }
                catch (Exception ex)
                {
                    ErrorRecorder?.setRecord(ex);
                }
                if (length > 0)
                {
                    if (length <= RecBuf.Length)
                    {
                        List<byte> tRecDatas = new List<byte>();
                        for (int i = 0; i < length; i++)
                            tRecDatas.Add(RecBuf[i]);
                        tTRBuf = tRecDatas.ToArray();
                        try
                        {
                            if (length > 17)
                            {

                            }
                            OnReceiveRespon?.Invoke(this, tTRBuf);
                        }
                        finally
                        {
                            if ((tClientSocket != null) && tClientSocket.Connected)
                                tClientSocket.BeginReceive(RecBuf, 0, RecBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), tClientSocket);//向系统投递下一个接收请求
                        }
                    }
                }
                else
                {
                    tClientSocket.Close();
                }
            }
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="hostAddress">服务器地址</param>
        /// <param name="port">服务器监听端口</param>
        public bool Connect(IPEndPoint hostAddress)
        {
            DestIPEndPoint = hostAddress;
            return Connect();
        }
        /// <summary>
        /// 关闭与服务器的连接
        /// </summary>
        public void CloseAll()
        {
            if (tClientSocket != null)
            {
                if (tClientSocket.Connected)
                    tClientSocket.Shutdown(SocketShutdown.Both);
                tClientSocket.Close();
                tClientSocket = null;
            }
        }

        /// <summary>
        /// 发送数据，发送前必须保证已经成功连接
        /// </summary>
        /// <param name="fSendDatas"></param>
        /// <returns></returns>
        public int Send(byte[] fSendDatas)
        {
            if ((tClientSocket != null) && tClientSocket.Connected)
            {
                return tClientSocket.Send(fSendDatas);
            }
            return -1;
        }
        public int Send(string Datas)
        {
            if (!string.IsNullOrEmpty(Datas))
            {
                byte[] tDatas = Encoding.UTF8.GetBytes(Datas);
                return Send(tDatas);
            }
            return -1;
        }

        public static int SendWithCallBack(IPEndPoint destIPEndPoint, byte[] datas, SocketRecResponCallBack OnRespon, int TimeOutMS = 1000)
        {
            byte[] RecBuf = new byte[4000];
            Socket tClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            Thread tSWBThd = null;
            long iTimeOutms = TimeOutMS;
            Stopwatch stopwatch = new Stopwatch();
            IAsyncResult tAResult = null;

            void SWRecCallBack(IAsyncResult asyncResult)
            {
                Socket remoteEP = (Socket)asyncResult.AsyncState;
                int length = 0;
                try
                {
                    length = remoteEP.EndReceive(asyncResult);
                    if (length > 0)
                    {
                        byte[] RecDatas = new byte[length];
                        for (int i = 0; i < length; i++)
                            RecDatas[i] = RecBuf[i];
                        OnRespon?.Invoke(remoteEP, RecDatas);
                    }
                }
                finally
                {
                    if (remoteEP != null)
                        remoteEP.Close();
                }
            }

            void thdMainRun()
            {
                try
                {
                    if (iTimeOutms > 0)
                    {
                        while (iTimeOutms - stopwatch.ElapsedMilliseconds > 0)
                        {
                            Thread.Sleep(1);
                            if ((tClientSocket == null) || ((tClientSocket != null) && (!tClientSocket.Connected)))
                            {
                                if (tClientSocket != null)
                                    tClientSocket.Close();
                                tClientSocket = null;
                                break;
                            }
                        }
                        if (tClientSocket != null)
                        {
                            tClientSocket.Close();
                            tClientSocket = null;
                        }
                    }
                }
                finally
                {
                    stopwatch.Stop();
                }
            }

            tClientSocket.Connect(destIPEndPoint);
            if (tClientSocket.Connected)
            {
                tAResult=tClientSocket.BeginReceive(RecBuf, 0, RecBuf.Length, SocketFlags.None, new AsyncCallback(SWRecCallBack), tClientSocket);//向系统投递下一个接收请求
                tClientSocket.Send(datas);
                tSWBThd = new Thread(thdMainRun);
                stopwatch.Start();
                tSWBThd.Start();
                return 1;
            }
            else
            {
                tClientSocket = null;
            }
            return 0;
        }

    }
}

